package edu.ustb.efws.pipeline.service;

import edu.ustb.efws.EfwsProperties;
import edu.ustb.efws.base.domain.Position;
import edu.ustb.efws.base.mapper.PositionMapper;
import edu.ustb.efws.pipeline.domain.RiskLog;
import edu.ustb.efws.pipeline.mapper.RiskLogMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 风险级别日志业务服务
 *
 * @author TS Group
 */
@Service
@Transactional(readOnly = true)
public class RiskLogService {
    private static final Logger LOGGER = LoggerFactory.getLogger(RiskLogService.class);

    private final RiskLogMapper logMapper;
    private final PositionMapper positionMapper;
    private final TableOptService tableOptService;
    private final EfwsProperties properties;

    @Autowired
    public RiskLogService(RiskLogMapper logMapper, PositionMapper positionMapper,
                          EfwsProperties properties, TableOptService tableOptService) {

        this.logMapper = logMapper;
        this.positionMapper = positionMapper;
        this.tableOptService = tableOptService;
        this.properties = properties;
    }

    /**
     * 创建新的日志表，日志是按照月分割的
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void createTable(){
        try{
            List<Position> positions = positionMapper.findAll();
            for(Position position: positions) {
                String tableName = buildTableName(position.getId());
                tableOptService.createIfAbsent(tableName, e -> {
                    logMapper.createTable(position.getId());
                    //创建分区
                    tableOptService.createPartition(e, properties.getStartMonth(),
                            (m, p) -> logMapper.createPartition(position.getId(), m, p));
                });
            }
        }catch (Exception e){
            LOGGER.error("Create risk log table fail error={}", e.getMessage());
        }
    }

    private String buildTableName(int positionId){
        return String.format("zlg_risk_%d", positionId);
    }

    /**
     * 创建分区
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void createPartition(){
        try{
            List<Position> positions = positionMapper.findAll();
            for(Position position: positions) {
                String tableName = buildTableName(position.getId());
                tableOptService.createPartition(tableName, properties.getStartMonth(),
                        (m, p) -> logMapper.createPartition(position.getId(), m, p));
            }
        }catch (Exception e){
            LOGGER.error("Create risk log table partition fail error={}", e.getMessage());
        }
    }

    /**
     * 删除分区
     *
     * @param fromMonthNum 开始月份
     * @param toMonthNum 结束月份
     * @param remark 备注
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void dropPartition(int fromMonthNum, int toMonthNum, String remark){
        try{
            List<Position> positions = positionMapper.findAll();
            for(Position position: positions) {
                String tableName = buildTableName(position.getId());
                tableOptService.dropPartition(tableName, fromMonthNum, toMonthNum, remark,
                        partition -> logMapper.dropPartition(position.getId(), partition));
            }
        }catch (Exception e){
            LOGGER.error("Drop risk log table partition fail error={}", e.getMessage());
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void save(List<RiskLog> logs){
        Map<String, Object> param = new HashMap<>(2, 1);
        param.put("positionId", logs.get(0).getPositionId());
        param.put("logs", logs);
        logMapper.insertBatch(param);
    }

    /**
     * 查询最后日志
     *
     * @param positionId 设备编号
     * @return 最后日志
     */
    public Optional<RiskLog> getLastOpt(int positionId){
        try{
            return Optional.ofNullable(logMapper.findLast(positionId));
        }catch (Exception e){
            LOGGER.warn("Get last risk fail positionId={}, error={}", positionId, e.getMessage());
            return Optional.empty();
        }
    }

    public Long count(int positionId, int month, Date from, Date to){
        return logMapper.count(positionId, month, from, to);
    }

    public List<RiskLog> query(int positionId, int month, Date from, Date to, int offset, int limit){
        return logMapper.find(positionId, month, from, to, offset, limit);
    }

}
